package com.linewell.util;

import com.alibaba.dubbo.common.utils.StringUtils;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.linewell.encryption.enums.SMFactoryEnum;
import com.linewell.encryption.pojo.SMInitInfo;
import com.linewell.encryption.services.SMEncryptionService;

import java.util.*;

public class test {
    public static void main(String[] args) throws Exception {

//      String keyValue = "kinsec19";
//      String sm2SignPath = "http://125.77.73.161:8880/Svr";
//      Integer sm2SignPrivateKeyIndex = 23;
//      Integer sm2PrivateKeyIndex = 1;


        // 获取系统公私钥
//		  CreateKeyService createKeyService = new CreateKeyServiceImpl();
//		  SM2KeyInfo sm2KeyInfo = createKeyService.createSM2Key();
//		  String pu = sm2KeyInfo.getPublicKey();
//		  String pr = sm2KeyInfo.getPrivateKey();
//        String sm4Key = createKeyService.createSM4Key();
//        System.out.println("sm4Key==" + sm4Key);
        //sm2 签名的
        String signPu = "BHje2utqIDxZC6hZLf5Q8cYNg5ncHJO8c926i+fit+p6T/pc8FZ5kEaqanTH5AfU1biiPTW29U4aFu+04U3YWaw=";
        String signPr = "duMHf7aZwcdlS+2vl0GciXWu5ob71dJHIHgqFn2+rWY=";
        //sm2 加密的
        String puKey = "BAvUp2k3EbD8m0tpKdKEWUaXz8itz2ze6DFQNxLeNtpWRjmn3ZtEsYGF2CDIANefWNfhlA/FBUE2I1XwaAGzEjY=";
        String prKey = "V8AI2ZsOnrD+Z2FVAVaJ5QsERQsLCCbhYP0fVZcAwe8=";
        //sm4 秘钥
        String sm4pKey = "90075EA510414A8234B179385A7E9055";

        //签名测试服务器
        String path = "http://125.77.73.161:8880/Svr";
        //账号
        String keyValue = "kinsec19";
        //23 的公钥证书
        String cert = "MIIC3zCCAoOgAwIBAgIQROw+dy4ELL1ioRw8SUUxjDAMBggqgRzPVQGDdQUAMGUxCzAJBgNVBAYTAkNOMRIwEAYDVQQIDAnnpo/lu7rnnIExEjAQBgNVBAcMCeemj+W3nuW4gjEVMBMGA1UECgwM5Yev54m55L+h5a6JMRcwFQYDVQQDDA7kv6HlrolTTTLmoLlDQTAeFw0xOTAzMDUwNjU4MzBaFw00OTAzMDUwNjU4MzBaMIGbMQswCQYDVQQGEwJDTjEcMBoGCCsGAQUFBwMEEw5raW5zZWNAMTI2LmNvbTESMBAGA1UECAwJ56aP5bu655yBMRIwEAYDVQQHDAnnpo/lt57luIIxGzAZBgNVBAoMEueJueaWsOS/oeaBr+WuieWFqDESMBAGA1UECwwJ5oqA5pyv6YOoMRUwEwYDVQQDDAzlh6/nibnkv6HlrokwWTATBgcqhkjOPQIBBggqgRzPVQGCLQNCAASkAtUfOgHsq83d+k5tOiuJ4sThosqj5Te5+awelNa7NGvv7v9eZ6bx6Gh2bMZ8WD1FFBwASphK+uR03RIDPmt+o4HbMIHYMAkGA1UdEwQCMAAwHQYDVR0OBBYEFH0LlnRMklgK4b0EA1oztYjJuT/pMIGeBgNVHSMEgZYwgZOAFLow2wk993IcGZBAcYiPvvCDVi2loWmkZzBlMQswCQYDVQQGEwJDTjESMBAGA1UECAwJ56aP5bu655yBMRIwEAYDVQQHDAnnpo/lt57luIIxFTATBgNVBAoMDOWHr+eJueS/oeWuiTEXMBUGA1UEAwwO5L+h5a6JU00y5qC5Q0GCEBjqHBVrH0tVfeR7FVmaPbMwCwYDVR0PBAQDAgP4MAwGCCqBHM9VAYN1BQADSAAwRQIgF28CXmua+d42B27e91cpqEtkMGLIsuvXD8hvJlg1WD0CIQC77lhQo19hYsy6DawFRgnWt8fQs7Wx+wAdVEIbyBf0/w==";

        SMInitInfo wucan = new SMInitInfo(SMFactoryEnum.SYSTEM.getAppId());
        //jce 密码机，   System 系统的
        SMInitInfo smInitInfo = new SMInitInfo(SMFactoryEnum.SYSTEM.getAppId());

        // 密码机加解密使用
        smInitInfo.setSm2KeyIndex(2);
        // 密码机签名使用
        smInitInfo.setSm2JceSignPublicKey(cert);
        smInitInfo.setSm2KeyPassword(keyValue);
        smInitInfo.setSm2SignPath(path);
        smInitInfo.setSm2SignPrivateKeyIndex(23);

        // 自己系统使用
        smInitInfo.setSm2PublicKey(puKey);
        smInitInfo.setSm2PrivateKey(prKey);
        smInitInfo.setSm2SignPublicKey(signPu);
        smInitInfo.setSm2SignPrivateKey(signPr);
        // 自己系统使用
        smInitInfo.setSm4Key(sm4pKey);
        // 密码机使用
        smInitInfo.setSm4KeyIndex(11);

        // 加解密使用对象实例化
        SMEncryptionService service = SMFactoryEnum.getService(smInitInfo);

        // sm2加解密
//        System.out.println("1==" + smInitInfo);
        String sign = service.encodeSM2(wucan);
        System.out.println("1==" + sign);
        SMInitInfo wwww = service.decodeSM2(sign, SMInitInfo.class);
        System.out.println("2==" + JSONObject.toJSONString(wwww));
//
//        // sm2加解密
        String input = "11111";
        String sign2 = service.encodeSM2(input);
        System.out.println("sign2==" + sign2);
        Integer signResult2 = service.decodeSM2(sign2, Integer.class);
        System.out.println("signResult2==" + signResult2);


     // 签名验签
        SMEncryptionService service222 = SMFactoryEnum.getService(smInitInfo);
        String sign11 = service222.signSM2("<?xml version=\"1.0\" encoding=\"utf-8\"?><License>123</License>");
        System.out.println("3==" + sign11);
        System.out.println("4==" + service222.verifySignSM2("<?xml version=\"1.0\" encoding=\"utf-8\"?><License>123</License>", sign11));

//
//        // 获取签名公钥
//        JCESM2SignCertService j = new JCESM2SignCertServiceImpl();
//        String fff = j.exportCert(path, 23);
//        System.out.println("6==" + fff);
//        String result222 = SVSClientUtils.exportCert(path, "20" + 23);
//        System.out.println("7==" + result222);
//
//        // sm4加解密
//        String signSm4 = service.encodeSM4ECB(wucan);
//        System.out.println("8==" + signSm4);
//        SMInitInfo wwwSm4 = service.decodeSM4ECB(signSm4, SMInitInfo.class);
//        System.out.println("9==" + JSONObject.toJSONString(wwwSm4));

//        // 获取签名公钥
//        JCESM2SignCertService jcesm2SignCertService = new JCESM2SignCertServiceImpl();
//        String exportCert = jcesm2SignCertService.exportCert(smInitInfo.getSm2SignPath(), 23);
//        System.out.println("9==" + exportCert);

        // 接口api 调试
//        String access_token = "ba28213f-e0f2-48ce-8ef7-6eb9a6d641a0";
//        String url = "http://127.0.0.1:8040/license-api-release";

        try {
//        	for(int i=0;i<5;i++) {
//        		test1(access_token, url, service);
//            	test2(access_token, url, service);
//            	test3(access_token, url, service);
//            	test4(access_token, url, service);
//        	}

//        	System.out.println("11==" + service.SM3(eee));






//        	String plainText = "车位";
////         	System.out.println("==="+JSONObject.parseObject(new String(plainText.getBytes("UTF-8")), String.class));
//         	System.out.println("==="+new String(plainText.getBytes("UTF-8")));
//
//         	String ooo1 = "guid=15d91d1e-2619-4f6c-878d-488ee4b4b081&appID=A008&businessID=001&ownerCode=743840215&timestamp=2019-05-06 14:11:30";
//         	System.out.println("===1"+service.signSM2(ooo1));
//         	String ooo2 = "guid=15d91d1e-2619-4f6c-878d-488ee4b4b081&appID=A008&businessID=001&licenseType=02800117&licenseFileNumber=003659951-350124100006011-000000000&timestamp=2019-05-06 14:11:30";
//         	System.out.println("===2"+service.signSM2(ooo2));
//
//         	System.out.println("===="+Base64Utils.byteToBase64(SM3Utils.hmac(Base64Utils.byteToBase64(SM3Utils.encrypt("1234@qwer")).getBytes(StandardCharsets.UTF_8), "a4b0055e99e4426da891fda6ef0be01c".getBytes(StandardCharsets.UTF_8))));
//         	eeeeeeeee(6.99);

        }catch (Exception e) {
			e.printStackTrace();
		}

    }

    private static void eeeeeeeee(Object secret) {
    	 if(secret instanceof String){
    		 System.out.println(secret.toString());
         }else {
        	 System.out.println(JSONObject.toJSONString(secret, SerializerFeature.WriteMapNullValue));
         }
    }

   /* // get 方式使用的SM2加解密
    private static void test1(String access_token, String url, SMEncryptionService service) throws Exception {

        HttpUtils httpclient = HttpUtils.getInstance();
        String time = System.currentTimeMillis() + "";
        // 参数加密
        String id = "110";
        String idSign = service.encodeSM2(id);

        // test1
        Map<String, String> parameterMap = new HashMap<>();
        parameterMap.put("id", idSign);
        parameterMap.put("time", time);
        parameterMap.put("access_token", access_token);
        // 签名排序
        String mapTest1String = returnParameterMap(parameterMap);
        // 签名
        String test1Sign = service.signSM2(mapTest1String);

        String test1Url = url + "/health/test1?" + "id=" + URLEncoder.encode(idSign, "UTF-8") + "&time=" + time + "&access_token=" + access_token + "&sign=" + URLEncoder.encode(test1Sign, "UTF-8");
        System.out.println("test1Url==" + test1Url);
        String resultTest1 = httpclient.sendHttpsGet(test1Url);
        System.out.println("resultTest1==" + resultTest1);
        JSONObject resultJson = JSONObject.parseObject(resultTest1);
        // {"data":"BAP3GztX59Zr/XB2/aXvMI+Qb0ZssB0/mPvkk1ofPzSPHdWIuDRcIDOh04hjTPWiX4e8faiMMpU1AEpEZ8P5AIzwOVXH8mCmI19xxcvtWfPUN6XnEx6PfIDD6YjAz5sYcrWkqH8R","head":{"message":"获取成功","sign":"MEUCIQCR6bvuyvZgUCjnjL/G/C0qyAhoJacLaEFOylM+x9C/XAIgcsatblPRwqxxVUfGUJCSsREg2of9s21kObb8QWbtLoo=","status":0,"time":1555494710986}}
        // 判断请求是否正常
        if (Objects.nonNull(resultJson) && Objects.equals(resultJson.getJSONObject("head").getIntValue("status"), 0)) {

        	// 验证签名排序
            String signString = returnResultMap(resultJson.get("data"), resultJson.getJSONObject("head").getString("time"));
            // 验证签名
            boolean isSign = service.verifySignSM2(signString, resultJson.getJSONObject("head").getString("sign"));
            System.out.println("isSign==" + isSign);
            // 解密

            String data = resultJson.getString("data");
            // 解密方式
            String idE = service.decodeSM2(data, String.class);
            System.out.println("idE==" + idE);

        }

    }

    // post 请求使用的SM2加解密
    private static void test2(String access_token, String url, SMEncryptionService service) throws Exception {

        HttpUtils httpclient = HttpUtils.getInstance();
        String time = System.currentTimeMillis() + "";
        // 参数加密
        String id = "测试";
        String idSign = service.encodeSM2(id);

        // 参数
        Map<String, String> parameterMap = new HashMap<>();
        parameterMap.put("id", idSign);
        parameterMap.put("time", time);
        parameterMap.put("access_token", access_token);
        String mapTest1String = returnParameterMap(parameterMap);
        System.out.println("mapTest1String==" + mapTest1String);
        // 签名
        String test1Sign = service.signSM2(mapTest1String);
        System.out.println("test1Sign==" + test1Sign);
        parameterMap.put("sign", test1Sign);

        String resultTest2 = httpclient.sendHttpPost( url + "/health/test2",parameterMap);
        System.out.println("resultTest2==" + resultTest2);
        JSONObject resultJson = JSONObject.parseObject(resultTest2);
        // 判断请求是否正常  {"data":{"name":"BBdcaJJbqvbDlQuI9+q7M/GGp38xJCcYZRzqRm655yd4jzLNRyYoi+4FE4n24DovSZql7ddYvbMct3Mg74ZS9Nk15UpvkeeotJSp+xOrKrfbmujRc/9V/tGIaD7cCazZLLOukP1bzYa79J2Cmohu","id":"110"},"head":{"message":"获取成功","sign":"MEUCIQDOhpl/QGZrV2nXZQvmYS4/M6Zn6qh32+FQJ55i8dyo0AIgGrxMtPbsESxC2zWtY+JpDZlSy13HIa1ozdR98I6aPIY=","status":0,"time":1555566657686}}
        if (Objects.nonNull(resultJson) && Objects.equals(resultJson.getJSONObject("head").getIntValue("status"), 0)) {
            // 验证签名
            String signString = returnResultMap(resultJson.get("data"), resultJson.getJSONObject("head").getString("time"));
            boolean isSign = service.verifySignSM2(signString, resultJson.getJSONObject("head").getString("sign"));
            System.out.println("isSign==" + isSign);
            // 解密
            String data = resultJson.getJSONObject("data").getString("name");
            System.out.println("data==" + data);
            // 解密方式
            String name = service.decodeSM2(data, String.class);
            System.out.println("name==" + name);

        }

    }



    // post 请求 使用的SM4加解密
    private static void test3(String access_token, String url, SMEncryptionService service) throws Exception {

        HttpUtils httpclient = HttpUtils.getInstance();
        String time = System.currentTimeMillis() + "";
        // 参数加密
        String id = "测试";
        String idSign = service.encodeSM4ECB(id);

        // 参数
        Map<String, String> parameterMap = new HashMap<>();
        parameterMap.put("id", idSign);
        parameterMap.put("time", time);
        parameterMap.put("access_token", access_token);
        // 签名参数排序
        String mapTest1String = returnParameterMap(parameterMap);
        System.out.println("mapTest1String==" + mapTest1String);
        // 签名
        String test3Sign = service.signSM2(mapTest1String);
        System.out.println("test3Sign==" + test3Sign);
        parameterMap.put("sign", test3Sign);

        String resultTest3 = httpclient.sendHttpPost( url + "/health/test3",parameterMap);
        System.out.println("resultTest3==" + resultTest3);
        JSONObject resultJson = JSONObject.parseObject(resultTest3);
        // 判断请求是否正常  {"data":["lTgWrF6Q2rzfxWed8pUFcQ==","/t8qqoCf60EkHkXJhnBS+A==","mjSBsp/N3qDgQu0wwQ0tpQ=="],"head":{"message":"获取成功","sign":"MEQCIEfri1OPY1+WNHZ9tuC38em8GldYzDNWCZUg87puvEZvAiBjv+2a9ym+qytmWm8bwkZb82aE7BQx7fpaka9qZsWMuw==","status":0,"time":1555571901548}}
        if (Objects.nonNull(resultJson) && Objects.equals(resultJson.getJSONObject("head").getIntValue("status"), 0)) {
            // 验证签名
            String signString = returnResultMap(resultJson.get("data"), resultJson.getJSONObject("head").getString("time"));
            boolean isSign = service.verifySignSM2(signString, resultJson.getJSONObject("head").getString("sign"));
            System.out.println("isSign==" + isSign);
            // 解密

            List<Object> listResult =  resultJson.getJSONArray("data");
            for(Object o:listResult) {
            	 // 解密方式
                String name = service.decodeSM4ECB(String.valueOf(o), String.class);
                System.out.println("name==" + name);
            }



        }

    }

    // post 请求 使用的SM4加解密
    private static void test4(String access_token, String url, SMEncryptionService service) throws Exception {

        HttpUtils httpclient = HttpUtils.getInstance();
        Map<String,String> map = new HashMap<>(16);
        // 参数加密
        String wu = service.encodeSM2("15005052911");
        long time = System.currentTimeMillis();
        map.put("time", time+"");
        map.put("access_token", access_token);
        map.put("id", wu);
        map.put("can", "352201199112150916");
        //参数排序
        String mapString = returnParameterMap(map);
        System.out.println("13==" + mapString);
        // 签名
        String canSign = service.signSM2(mapString);
        map.put("sign", canSign);
        System.out.println("12==" + JSONObject.toJSONString(map));
        String result = httpclient.sendHttpPost(url+ "/health/test4", map);
        System.out.println("11==" + result);

        JSONObject resultJson = JSONObject.parseObject(result);
        JSONObject data = resultJson.getJSONObject("data");
        JSONArray info = data.getJSONArray("info");
        info.forEach(in -> {
            try {
                //解密
                System.out.println(service.decodeSM2(in.toString(), String.class));
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }*/



    /**
     * 参数排序整合
     */
    private static String returnParameterMap(Map<String, String> map) {
        StringBuilder sb = new StringBuilder();
        if (Objects.nonNull(map)) {
            List<String> keyList = new ArrayList<>(map.keySet());
            Collections.sort(keyList);
            for (String key : keyList) {
                String value = map.get(key);
                if (StringUtils.isNotEmpty(value) && !Objects.equals("sign", key)) {
                    sb.append(key).append("=").append(value).append("&");
                }
            }
        }
        return sb.substring(0, sb.length() - 1);
    }


    /**
     * 返回值签名规则
     */
    private static String returnResultMap(Object result, String time) {
        if (Objects.nonNull(result)) {
            return "data" + "=" + JSONObject.toJSONString(result, SerializerFeature.WriteMapNullValue) + "&" + "time" + "=" + time;
        }
        return "time" + "=" + time;
    }



    /**
     * 出参参数加密
     *
     * @param wMap        出参参数
     * @param parameter   字段
     * @param signService 加密service
     * @param signType    加密类型
     * @return 加密后的出参
     */
    private Object returnObjectString(Object wMap, String parameter, SMEncryptionService signService, String signType) throws Exception {
        String[] parameterSplit = parameter.split("/");

        // 是否包含# # 代表的是列表
        String parameterOne = parameterSplit[0];
        if (parameterOne.contains("#")) {
            JSONArray array = JSONArray.parseArray(JSONObject.toJSONString(wMap, SerializerFeature.WriteMapNullValue));
            JSONArray returnArray = new JSONArray();
            for (Object object : array) {
                returnArray.add(returnCLData(object, parameterSplit, parameter, parameterOne, signService, signType));
            }
            return returnArray;
        } else {
            // 值为：data:11111 形式填*
            if (Objects.equals(parameterOne, "*")) {
                return returnCLData(wMap, parameterSplit, parameter, parameterOne, signService, signType);
            } else {
                JSONObject object = JSONObject.parseObject(JSONObject.toJSONString(wMap, SerializerFeature.WriteMapNullValue));
                Object zObject = object.get(parameterOne);
                Object cll = returnCLData(zObject, parameterSplit, parameter, parameterOne, signService, signType);
                object.put(parameterOne, cll);
                return object;
            }
        }
    }


    /**
     * 出参参数加密
     *
     * @param cl             处理数据
     * @param parameterSplit 数据key层次字符串
     * @param parameterOne   第一层key名称
     * @param signService    加密对象
     * @param signType       加密类型
     * @return 加密后的出参
     */
    private Object returnCLData(Object cl, String[] parameterSplit, String parameter, String parameterOne, SMEncryptionService signService, String signType) throws Exception {
        Object s = cl;
        if (parameterSplit.length == 1) {
            if (Objects.equals(parameterOne, "#") || !parameterOne.contains("#") || Objects.equals(parameterOne, "*")) {
                String decode = encodeSM2OrSM4(String.valueOf(cl), signService, signType);
                if (StringUtils.isNotEmpty(decode)) {
                    return decode;
                }
            } else {
                JSONObject object = JSONObject.parseObject(JSONObject.toJSONString(cl, SerializerFeature.WriteMapNullValue));
                if (Objects.isNull(object)) {
                    return cl;
                }
                String parameterTwo;
                if (parameterOne.contains("#")) {
                    String[] parameterSplitTwo = parameterOne.split("#");
                    parameterTwo = parameterSplitTwo[1];
                } else {
                    parameterTwo = parameterOne;
                }
                String mapString = object.getString(parameterTwo);
                if (Objects.isNull(mapString)) {
                    return cl;
                }
                // 最后一层处理数据
                String decode = encodeSM2OrSM4(mapString, signService, signType);
                if (StringUtils.isNotEmpty(decode)) {
                    object.put(parameterTwo, decode);
                } else {
                    object.put(parameterTwo, mapString);
                }
                s = object;
            }

        } else {
            String parameterTwo = parameter.substring((parameterOne + "/").length());
            s = returnObjectString(cl, parameterTwo, signService, signType);
        }
        return s;
    }


    /**
     * 参数解密
     *
     * @param wMap        参数
     * @param parameter   格式
     * @param signService 解密service
     * @return 返回解密后的参数
     */
    private String returnParameterString(String wMap, String parameter, SMEncryptionService signService, String signType) throws Exception {

        String[] parameterSplit = parameter.split("/");
        if (parameterSplit.length == 0) {
            // 就一层处理数据
            String decode = decodeSM2OrSM4(wMap, signService, signType);
            if (StringUtils.isNotEmpty(decode)) {
                return decode;
            }
            return wMap;
        }
        JSONObject object = JSONObject.parseObject(wMap);
        if (Objects.isNull(object)) {
            return wMap;
        }
        String mapString = object.getString(parameterSplit[0]);
        if (StringUtils.isEmpty(mapString)) {
            return wMap;
        }
        if (parameterSplit.length == 1) {
            // 最后一层处理数据
            String decode = decodeSM2OrSM4(mapString, signService, signType);
            if (StringUtils.isNotEmpty(decode)) {
                object.put(parameterSplit[0], decode);
            } else {
                object.put(parameterSplit[0], mapString);
            }
        } else {
            String parameterTwo = parameter.substring((parameterSplit[0] + "/").length());
            String s = returnParameterString(mapString, parameterTwo, signService, signType);
            object.put(parameterSplit[0], s);
        }
        return JSONObject.toJSONString(object, SerializerFeature.WriteMapNullValue);

    }

    /**
     * 使用哪种加密方式
     *
     * @param var1        加密数据
     * @param signService 加密对象
     * @param signType    解密类型
     * @return 密文
     * @throws Exception 异常
     */
    private String encodeSM2OrSM4(String var1, SMEncryptionService signService, String signType) throws Exception {
        if (Objects.equals(signType, "SM4")) {
            return signService.encodeSM4ECB(var1);
        }
        return signService.encodeSM2(var1);
    }

    /**
     * 使用哪种解密方式
     *
     * @param var1        密文
     * @param signService 解密对象
     * @param signType    解密类型
     * @return 明文
     * @throws Exception 异常
     */
    private String decodeSM2OrSM4(String var1, SMEncryptionService signService, String signType) throws Exception {
        if (Objects.equals(signType, "SM4")) {
            return signService.decodeSM4ECB(var1, String.class);
        }
        return signService.decodeSM2(var1, String.class);
    }

}

